package com.free.note.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.free.common.core.constant.RedisNodeCacheConstants;
import com.free.common.core.enums.Classify;
import com.free.common.core.utils.DateUtils;
import com.free.common.core.web.page.TableDataInfo;
import com.free.compilation.domain.ZoneCompilation;
import com.free.compilation.domain.ZoneCompilationChapter;
import com.free.compilation.domain.ZoneCompilationStep;
import com.free.compilation.mapper.ZoneCompilationMapper;
import com.free.compilation.service.ZoneCompilationChapterService;
import com.free.compilation.service.ZoneCompilationStepService;
import com.free.note.domain.NoteRandomCount;
import com.free.note.domain.TypeTree;
import com.free.note.domain.ZoneNote;
import com.free.note.feign.FileClientService;
import com.free.note.mapper.ZoneNoteMapper;
import com.free.system.api.RemoteSystemService;
import com.free.system.api.domain.SysDictData;
import io.micrometer.core.instrument.util.StringEscapeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 笔记Service业务层处理
 *
 * @author YHL
 * @date 2023-02-26
 */
@Service
@Slf4j
public class ZoneNoteService extends ServiceImpl<ZoneNoteMapper, ZoneNote> {


    private final List classList = new ArrayList<>(Arrays.asList(105, 107, 110, 111));

    @Value("${base.url}")
    String baseUrl;

    @Autowired
    TypeTreeService typeTreeService;

    @Autowired
    NoteRandomCountService noteRandomCountService;
    @Autowired
    ZoneCompilationStepService zoneCompilationStepService;
    @Autowired
    ZoneCompilationMapper compilationMapper;
    @Autowired
    FileClientService fileClientService;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    ZoneCompilationChapterService zoneCompilationChapterService;
    @Autowired
    RemoteSystemService remoteSystemService;

    /**
     * 查询笔记
     *
     * @param id 笔记主键
     * @return 笔记
     */
    public ZoneNote selectZoneNoteById(Long id) {
        return this.baseMapper.selectById(id);
    }

    /**
     * 查询笔记列表
     *
     * @param zoneNote 笔记
     * @return 笔记
     */
    public List<ZoneNote> selectZoneNoteList(ZoneNote zoneNote) {
        QueryWrapper<ZoneNote> wrapper = new QueryWrapper<>();
        wrapper.like(ObjectUtils.isNotEmpty(zoneNote.getTitle()), "title", zoneNote.getTitle());
        wrapper.like(ObjectUtils.isNotEmpty(zoneNote.getClassify()), "classify", zoneNote.getClassify());
        wrapper.like(ObjectUtils.isNotEmpty(zoneNote.getExternalDisplay()), "external_display", zoneNote.getExternalDisplay());
        wrapper.like(ObjectUtils.isNotEmpty(zoneNote.getAiAudioToText()), "ai_audio_to_text", zoneNote.getAiAudioToText());
        wrapper.like(ObjectUtils.isNotEmpty(zoneNote.getExternalDisplay()), "external_display", zoneNote.getExternalDisplay());
        wrapper.orderByDesc("id");
        List<ZoneNote> zoneNotes = this.baseMapper.selectList(wrapper);
        zoneNotes.forEach(note -> {
            List<ZoneCompilation> compilations = this.baseMapper.selectRelevanceCompilation(note.getId());
            note.setCompilations(compilations);
        });
//        SELECT * from zone_compilation WHERE id in ( select compilation_id from zone_compilation_step where note_id = 700 )
        return zoneNotes;
    }

    /**
     * 新增笔记
     *
     * @param zoneNote 笔记
     * @return 结果
     */
    public ZoneNote insertZoneNote(ZoneNote zoneNote) {
        zoneNote.setCreateTime(DateUtils.getNowDate());
        setNewLabel(zoneNote);
        if (ObjectUtil.equal(zoneNote.getClassify(), 124)) {
            zoneNote.setFilePath(zoneNote.getContent());
            zoneNote.setAiAudioToText(1);
        }else {
            zoneNote.setAiAudioToText(0);
        }
        int insert = this.baseMapper.insert(zoneNote);
//        fileSynchronization(zoneNote);
//        redisTemplate.delete(RedisNodeCacheConstants.getShowAgainRandomList());
        return zoneNote;
    }

    private void setNewLabel(ZoneNote zoneNote) {
        if (ObjectUtils.isNotEmpty(zoneNote.getNewLabel())) {
            TypeTree typeTree = new TypeTree();
            if (ObjectUtils.isNotEmpty(zoneNote.getTreeId())) {
                String[] split = zoneNote.getTreeId().split(",");
                Long pid = Long.parseLong(split[split.length - 1]);
                typeTree.setPid(pid);
            }
            typeTree.setLabel(zoneNote.getNewLabel());
            Long count = typeTreeService.getBaseMapper().selectCount(new QueryWrapper<>(typeTree));
            if (count == 0) {
                typeTreeService.save(typeTree);
                zoneNote.setTreeId(zoneNote.getTreeId() + "," + typeTree.getId());
            }
        }
    }

    /**
     * 修改笔记
     *
     * @param zoneNote 笔记
     * @return 结果
     */
    public ZoneNote updateZoneNote(ZoneNote zoneNote) {
        zoneNote.setUpdateTime(DateUtils.getNowDate());
        setNewLabel(zoneNote);
        int updateZoneNote = this.baseMapper.updateById(zoneNote);
//        fileSynchronization(zoneNote);
//        redisTemplate.delete(RedisNodeCacheConstants.getShowAgainRandomList());
        return zoneNote;
    }

    /**
     * 批量删除笔记
     *
     * @param ids 需要删除的笔记主键
     * @return 结果
     */
    public int deleteZoneNoteByIds(Long[] ids) {
//        redisTemplate.delete(RedisNodeCacheConstants.getShowAgainRandomList());

        List<Long> longs = Arrays.asList(ids);
        longs.forEach(e -> {
            QueryWrapper<ZoneCompilationStep> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("note_id", e);
            Long aLong = zoneCompilationStepService.getBaseMapper().selectCount(queryWrapper);
            Assert.isTrue(aLong == 0, "有关联的合集，无法删除");
        });

        return this.baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除笔记信息
     *
     * @param id 笔记主键
     * @return 结果
     */
    public int deleteZoneNoteById(Long id) {
//        redisTemplate.delete(RedisNodeCacheConstants.getShowAgainRandomList());
        return this.baseMapper.deleteById(id);
    }

    /**
     * 随机获取一个
     *
     * @return
     */
    public ZoneNote randomOne(String compilationId) {
        ZoneNote zoneNote = (ZoneNote) redisTemplate.opsForList().leftPop(RedisNodeCacheConstants.getShowAgainRandomList(compilationId));
        if (ObjectUtil.isEmpty(zoneNote)) {
            Set members = redisTemplate.opsForSet().members(RedisNodeCacheConstants.getNotShowAgainSet());
            QueryWrapper<ZoneNote> queryWrapper = new QueryWrapper();
            queryWrapper.notIn(ObjectUtil.isNotEmpty(members), "id", members).in("classify", "101", "109 ").orderByAsc(" rand()")
                    .apply(ObjectUtil.isNotEmpty(compilationId), "id in ( select note_id from zone_compilation_step where  deleted = 0 AND compilation_id =   " + compilationId + ")");
            List<ZoneNote> zoneNotes = this.baseMapper.selectList(queryWrapper);
            redisTemplate.opsForList().rightPushAll(RedisNodeCacheConstants.getShowAgainRandomList(compilationId), zoneNotes);
            zoneNote = (ZoneNote) redisTemplate.opsForList().leftPop(RedisNodeCacheConstants.getShowAgainRandomList(compilationId));
            Assert.notNull(zoneNote, "没有合适的题型");
        }
        Long id = zoneNote.getId();
        NoteRandomCount byId = noteRandomCountService.getById(id);
        if (byId == null) {
            byId = new NoteRandomCount();
            byId.setNoteId(id);
//            byId.setId(id);
            byId.setRandomCount(0L);
        }
        byId.setRandomCount(byId.getRandomCount() + 1);
        noteRandomCountService.saveOrUpdate(byId);
        return zoneNote;
    }

    /**
     * @param id
     */
    public void notShowAgain(Long id) {
        redisTemplate.opsForSet().add(RedisNodeCacheConstants.getNotShowAgainSet(), id);
    }

    /**
     *
     */
    public Long getRemainingQuantity(String compilationId) {
        return redisTemplate.opsForList().size(RedisNodeCacheConstants.getShowAgainRandomList(compilationId));
    }

    public void refreshQuantity(String compilationId) {
        redisTemplate.delete(RedisNodeCacheConstants.getShowAgainRandomList(compilationId));
    }

    /**
     * @return
     */
    public ZoneNote getNeedRecognitionOne() {
        QueryWrapper<ZoneNote> wrapper = new QueryWrapper<>();
        wrapper.eq("classify", Classify.PIC.getClassify());
        wrapper.eq("ai_recognition", 0);
        Page<ZoneNote> zoneNotePage = this.baseMapper.selectPage(new Page<>(1, 1), wrapper);
        return ObjectUtil.isNotEmpty(zoneNotePage.getRecords()) ? zoneNotePage.getRecords().get(0) : null;
    }

    /**
     * @param classify
     * @return
     */
    public ZoneNote getRandomOneByClassify(String classify) {
        Object obj = redisTemplate.opsForList().leftPop(RedisNodeCacheConstants.getRandomClassifyIds(classify));
        if (ObjectUtil.isEmpty(obj)) {
            List<Integer> ids = this.baseMapper.randomOne(classify);
            if (ObjectUtil.isEmpty(ids)) {
                return null;
            }
            redisTemplate.opsForList().leftPushAll(RedisNodeCacheConstants.getRandomClassifyIds(classify), ids);
            obj = redisTemplate.opsForList().leftPop(RedisNodeCacheConstants.getRandomClassifyIds(classify));
        }
        ZoneNote zoneNote = this.baseMapper.selectById(obj.toString());
        if (ObjectUtil.isEmpty(zoneNote)) {
            return null;
        }
        //查询关联的合集
        ZoneCompilationStep step = new ZoneCompilationStep();
        step.setNoteId(zoneNote.getId());
        List<ZoneCompilationStep> steps = this.zoneCompilationStepService.selectZoneCompilationStepList(step);
        if (ObjectUtil.isNotEmpty(steps)) {
            List<ZoneCompilation> zoneCompilations = this.compilationMapper.selectBatchIds(steps.stream().map(ZoneCompilationStep::getCompilationId).collect(Collectors.toList()));
            zoneNote.setCompilations(zoneCompilations);
        }
        return zoneNote;
    }
//    @Override
//    public IPage<User> getLimit() {
//        // 参数一:当前页面 currentPage  参数二：每页展示数 pageSize
//        Page<User> page = new Page<>(1, 3);
//        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.like("realname", "高");
//        IPage<User> userIPage = userMapper.selectPage(page, wrapper);
//        return userIPage;
//    }

    public List<String> getSwiperList() {
        QueryWrapper<ZoneNote> wrapper = new QueryWrapper<>();
        wrapper.eq("classify", 110);
        wrapper.eq("external_display", 1);
        wrapper.orderByDesc("classify", "RAND()");
        Page<ZoneNote> page = this.baseMapper.selectPage(new Page<>(1, 10), wrapper);
        List<String> retList = new ArrayList<>();
        page.getRecords().forEach(note -> {
            String uri = Base64.decodeStr(note.getContent());
            retList.add(baseUrl + uri);
        });
        return retList;
    }

    public ZoneNote getNeedFileSynchronization() {
        QueryWrapper<ZoneNote> wrapper = new QueryWrapper<>();
        wrapper.eq("file_synchronization", 0);
        Page<ZoneNote> zoneNotePage = this.baseMapper.selectPage(new Page<>(1, 1), wrapper);
        return ObjectUtil.isNotEmpty(zoneNotePage.getRecords()) ? zoneNotePage.getRecords().get(0) : null;
    }
    //    开启定时

    /**
     * 同步到anki
     */
    @Scheduled(cron = " 0 0/1 * * * ?")
    public void ankiAsyncAnalyze() {
        List<ZoneCompilationStep> steps = zoneCompilationStepService.getNeedAnkiAsyncAnalyze();
        TableDataInfo list = remoteSystemService.list(new SysDictData());
        List<SysDictData> totalDictData = JSONUtil.toList(JSONUtil.toJsonStr(list.getRows()), SysDictData.class);

        steps.forEach(step -> {
            //设值已同步状态
            step.setIsAsyncAnki(1L);
            zoneCompilationStepService.updateById(step);
            ZoneNote note = this.selectZoneNoteById(step.getNoteId());
            AtomicReference<String> deck = new AtomicReference<>("所有知识::游离天性");
            if (ObjectUtil.isEmpty(note)) {
                return;
            }
            //只要指定的类型
            List<Integer> classList = new ArrayList<>();
            classList.add(100);
            classList.add(109);
            classList.add(101);
            if (!classList.contains(note.getClassify())) {
                return;
            }
            //下面开始拼接
            ZoneCompilation compilation = compilationMapper.selectById(step.getCompilationId());
            if (ObjectUtil.isNotEmpty(compilation)) {
                deck.set(deck.get() + "::" + compilation.getTitle());
            }
            ZoneCompilationChapter compilationChapter = zoneCompilationChapterService.getById(step.getChapterId());
            if (ObjectUtil.isNotEmpty(compilationChapter)) {
                deck.set(deck.get() + "::" + compilationChapter.getChapterName());
            }
            //循环查找唯一的字典
            List<SysDictData> rows = totalDictData.stream().filter(item -> item.getDictCode() + 0 == note.getClassify() + 0).collect(Collectors.toList());
            rows.forEach(item -> {
                deck.set(deck.get() + "::" + item.getDictLabel());
            });

//            System.out.println(deck.get());
            //判断anki里面有没有这个deck
            String post = HttpUtil.post("http://192.168.2.120:8765", "{\"action\":\"deckNames\",\"version\":6}");
            JSONObject jsonObject = JSONUtil.parseObj(post);
            JSONArray deckArray = jsonObject.getJSONArray("result");
            //比较生成的在获取的deck里有没有
            if (!deckArray.contains(deck.get())) {
                //添加deck
                HttpUtil.post("http://192.168.2.120:8765", "{\"action\":\"createDeck\",\"version\":6,\"params\":{\"deck\":\"" + deck.get() + "\"}}");
            }
            //添加笔记
//            HttpUtil.post("http://192.168.2.120:8765", "{\"action\":\"addNotes\",\"version\":6,\"params\":{\"notes\":{{\"deckName\":\"" + deck.get() + "\",\"modelName\":\"简答题\",\"fields\":{\"正面\":\"" + note.getTitle() + "\",\"背面\":\"" + Base64.decodeStr(note.getContent()) + "\"}]}}}");
            String content = Base64.decodeStr(note.getContent());
            //双引号替换成单引号
            if (ObjectUtil.isEmpty(content)) {

//                content = "             —— 《" + compilation.getTitle() + "》";
                content = "<div class='compilation'>" + "             —— 《" + compilation.getTitle() + "》" + "</div>";
            }
//            content = content.replaceAll("\"", "'");
//            content = content.replaceAll("\n", "\\n");
//            content = content.replaceAll("\t", "\\t");
             content = StringEscapeUtils.escapeJson(content);
            String title = StringEscapeUtils.escapeJson(note.getTitle());
            title = step.getId() + "、" + title;
            String posted = HttpUtil.post("http://192.168.2.120:8765", "{" +
                    "    \"action\": \"addNotes\"," +
                    "    \"version\": 6," +
                    "    \"params\": {" +
                    "        \"notes\": [" +
                    "            {" +
                    "                \"deckName\": \"" + deck.get() + "\"," +
                    "                \"modelName\": \"问答题\"," +
                    "                \"fields\": {" +
                    "                    \"正面\": \"" + title + "\"," +
                    "                    \"背面\": \"" + content + "\"" +
                    "                }" +
                    "            }" +
                    "        ]" +
                    "    }" +
                    "}");
            // 检测添加的结果是否是"error": null，否则打印
            if (JSONUtil.getByPath(JSONUtil.parse(posted), "error") != null) {
                System.out.println("添加失败：" + JSONUtil.getByPath(JSONUtil.parse(posted), "error"));
                System.out.println("添加的结果：" + posted);
                System.out.println("deck：" + deck);
                System.out.println("问题：" + note.getTitle());
                System.out.println("答案：" + content);
                System.out.println("--------------------------------------------");
            }

            //设值已同步状态
            note.setFileSynchronization(1);
            this.updateById(note);
        });
        //触发同步
        HttpUtil.post("http://192.168.2.120:8765", "{\"action\":\"sync\",\"version\":6}");

    }
}
